package org.openfans.web.listener;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openfans.web.clickstream.OpenfansClickstream;

/**
 * Description：<br>
 * Date：2006-5-29<br>
 * 
 * @author pesome<br>
 * @email:pesome@gmail.com<br>
 */
public class OpenfansClickstreamListener implements ServletContextListener,
		HttpSessionListener {
	private static final Log log = LogFactory
			.getLog(OpenfansClickstreamListener.class);

	/** The servlet context attribute key. */
	public static final String CLICKSTREAMS_ATTRIBUTE_KEY = "clickstreams";

	/** The current clickstreams, keyed by session ID. */
	private Map<String, Object> clickstreams;

	public OpenfansClickstreamListener() {
		log.debug("ClickstreamLogger constructed");

		clickstreams = Collections
				.synchronizedMap(new HashMap<String, Object>());
	}

	/**
	 * Notification that the ServletContext has been initialized.
	 * 
	 * @param sce
	 *            The context event
	 */
	public void contextInitialized(ServletContextEvent sce) {
		log.debug("ServletContext initialised");
		sce.getServletContext().setAttribute(CLICKSTREAMS_ATTRIBUTE_KEY,
				clickstreams);
	}

	/**
	 * Notification that the ServletContext has been destroyed.
	 * 
	 * @param sce
	 *            The context event
	 */
	public void contextDestroyed(ServletContextEvent sce) {
		log.debug("ServletContext destroyed");
		// help gc, but should be already clear except when exception was thrown
		// during sessionDestroyed
		clickstreams.clear();
	}

	/**
	 * Notification that a Session has been created.
	 * 
	 * @param hse
	 *            The session event
	 */
	public void sessionCreated(HttpSessionEvent hse) {
		final HttpSession session = hse.getSession();
		if (log.isDebugEnabled()) {
			log.debug("Session " + session.getId()
					+ " was created, adding a new clickstream.");
		}

		Object attrValue = session
				.getAttribute(OpenfansClickstream.SESSION_ATTRIBUTE_KEY);
		if (attrValue != null) {
			log.warn("Session " + session.getId()
					+ " already has an attribute named "
					+ OpenfansClickstream.SESSION_ATTRIBUTE_KEY + ": "
					+ attrValue);
		}

		final OpenfansClickstream clickstream = new OpenfansClickstream();
		session.setAttribute(OpenfansClickstream.SESSION_ATTRIBUTE_KEY,
				clickstream);
		clickstreams.put(session.getId(), clickstream);
	}

	/**
	 * Notification that a session has been destroyed.
	 * 
	 * @param hse
	 *            The session event
	 */
	public void sessionDestroyed(HttpSessionEvent hse) {
		final HttpSession session = hse.getSession();

		// check if the session is not null (expired)
		if (session != null) {
			if (log.isDebugEnabled()) {
				log
						.debug("Session "
								+ session.getId()
								+ " was destroyed, logging the clickstream and removing it.");
			}

			final OpenfansClickstream stream = (OpenfansClickstream) clickstreams
					.get(session.getId());
			if (stream == null) {
				log.warn("Session " + session.getId()
						+ " doesn't have a clickstream.");
			} else {
				try {
					log.debug(stream);
				} catch (Exception e) {
					log.error(e.getMessage(), e);
				} finally {
					clickstreams.remove(session.getId());
				}
			}
		}
	}
}